package com.niiwoo.civet.user.service.local;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.niiwoo.civet.system.dto.common.MessageTemplateDto;
import com.niiwoo.civet.system.service.SysMessageTemplate;
import com.niiwoo.civet.user.constants.OrgRedisConstants;
import com.niiwoo.civet.user.dao.entity.*;
import com.niiwoo.civet.user.dao.mapper.*;
import com.niiwoo.civet.user.dto.request.OrganizationInfoReqDTO;
import com.niiwoo.civet.user.dto.request.OrganizationRequestDTO;
import com.niiwoo.civet.user.dto.response.OrganizationInfoRespDTO;
import com.niiwoo.civet.user.dto.response.organization.OrganizationBaseConfigRespDTO;
import com.niiwoo.civet.user.dto.response.organization.OrganizationLoanConfigRespDTO;
import com.niiwoo.civet.user.enums.OrganizationInfoStatusEnum;
import com.niiwoo.tripod.base.component.PrivacyMasks;
import com.niiwoo.tripod.provider.exception.BizException;
import com.niiwoo.tripod.service.component.SnowflakeIdWorker;
import com.niiwoo.tripod.sms.ISmsSendService;
import com.niiwoo.tripod.tiancheng.component.TianchengVerNameService;
import com.niiwoo.tripod.tiancheng.enums.FunctionCodeEnum;
import com.niiwoo.tripod.tiancheng.request.qdp.VerNameRequset;
import com.niiwoo.tripod.tiancheng.response.qdp.VerNameResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.time.FastDateFormat;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * @Description: 机构服务
 * @Author:LiJian
 * @Date:2017/12/14
 */
@Slf4j
@Service
public class OrganizationService {

    @Autowired
    private PrivacyMasks privacyMasks;

    @Autowired
    private SnowflakeIdWorker snowflakeIdWorker;

    @Autowired
    private OrganizationInfoMapperExt organizationInfoMapper;

    @Autowired
    private OrganizationBaseConfigMapperExt organizationBaseConfigMapperExt;

    @Autowired
    private OrganizationLoanConfigMapperExt organizationLoanConfigMapperExt;

    @Autowired
    private OrganizationManageFeeRatioConfigMapperExt organizationManageFeeRatioConfigMapperExt;

    @Reference(version = "1.0.0")
    SysMessageTemplate sysMessageTemplate;

    @Autowired
    private TianchengVerNameService tianchengVerNameService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    SMSRecordMapperExt smsRecordMapperExt;

    @Autowired
    private ISmsSendService smsSendService;

    @Value(value = "${smsService.enable:true}")
    private Boolean enable;

    private boolean isEnableSMS() {
        return enable;
    }

    /**
     * 根据机构类型获取机构信息（解密后）
     *
     * @param type
     * @return
     */
    public OrganizationInfo getOrganizationInfoByType(Byte type) {
        OrganizationInfo organizationInfo = organizationInfoMapper.selectOrgByType(type);
        if (organizationInfo != null) {
            String legalPersonPhoneNumber = organizationInfo.getLegalPersonPhoneNumber();
            organizationInfo.setLegalPersonPhoneNumber(StringUtils.isNoneBlank(legalPersonPhoneNumber) ? privacyMasks.decryptPrivacy(legalPersonPhoneNumber) : null);
            String agentIdentityCard = organizationInfo.getAgentIdentityCard();
            organizationInfo.setAgentIdentityCard(StringUtils.isNoneBlank(agentIdentityCard) ? privacyMasks.decryptPrivacy(agentIdentityCard) : null);
            String agentPhoneNumber = organizationInfo.getAgentPhoneNumber();
            organizationInfo.setAgentPhoneNumber(StringUtils.isNoneBlank(agentPhoneNumber) ? privacyMasks.decryptPrivacy(agentPhoneNumber) : null);
        }
        return organizationInfo;
    }

    @Transactional
    public boolean updateUserOrgInfo(OrganizationRequestDTO orgInfoReqDto) {
        OrganizationInfo orgInfo = new OrganizationInfo();
        orgInfo.setId(orgInfoReqDto.getId());
        orgInfo.setOrganizationCode(orgInfoReqDto.getOrganizationCode());
        orgInfo.setOrganizationName(orgInfoReqDto.getOrganizationName());
        orgInfo.setAccountOpeningBankLicense(orgInfoReqDto.getAccountOpeningBankLicense());
        orgInfo.setRepresentative(orgInfoReqDto.getRepresentative());
        orgInfo.setAccountOpeningBankLicense(orgInfoReqDto.getAccountOpeningBankLicense());
        orgInfo.setTaxId(orgInfoReqDto.getTaxId());
        orgInfo.setUnifiedSocialCreditCode(orgInfoReqDto.getUnifiedSocialCreditCode());
        orgInfo.setInstitutionalReditCode(orgInfoReqDto.getInstitutionalReditCode());
        orgInfo.setRepresentative(orgInfoReqDto.getRepresentative());
        orgInfo.setLegalPersonPhoneNumber(orgInfoReqDto.getLegalPersonPhoneNumber());
        orgInfo.setEmail(orgInfoReqDto.getEmail());
        orgInfo.setCharterCode(orgInfoReqDto.getCharterCode());
        orgInfo.setCorporateContactsName(orgInfoReqDto.getCorporateContactsName());
        orgInfo.setContactsPhoneName(StringUtils.isNotEmpty(orgInfoReqDto.getContactsPhoneName()) ? privacyMasks.encryptPrivacy(orgInfoReqDto.getContactsPhoneName()) : orgInfoReqDto.getContactsPhoneName());
        orgInfo.setUpdateManager(orgInfoReqDto.getUpdateManager());//系统修改默认id
        orgInfo.setUpdateTime(orgInfoReqDto.getUpdatetime());
        orgInfo.setLegalPersonCertNumber(StringUtils.isNotEmpty(orgInfoReqDto.getLegalPersonCertNumber()) ? privacyMasks.encryptPrivacy(orgInfoReqDto.getLegalPersonCertNumber()) : orgInfoReqDto.getLegalPersonCertNumber());
        orgInfo.setOrgNo(orgInfoReqDto.getOrgNo());
        orgInfo.setOrgPublicAccount(orgInfoReqDto.getOrgPublicAccount());
        orgInfo.setBankCode(orgInfoReqDto.getBankCode());

        int flag = organizationInfoMapper.updateByPrimaryKeySelective(orgInfo);
        return flag > 0;
    }

    /**
     * 根据机构编码获取启用机构信息
     *
     * @param orgCode
     * @return
     */
    public OrganizationInfo getEnableOrgInfoByOrgCode(String orgCode) {
        return organizationInfoMapper.selectLastOneByOrgCodeAndStatus(orgCode, OrganizationInfoStatusEnum.ENABLE.getStatus());
    }

    public OrganizationInfo getByOrgId(String orgId) {
        return organizationInfoMapper.selectByPrimaryKey(orgId);
    }

    /**
     * 批量查询机构信息
     * @param orgIds 机构id
     * @return list
     */
    public List<OrganizationInfo> getByOrgIdList(Set<String> orgIds){
        return organizationInfoMapper.selectByPrimaryKeyList(orgIds);
    }

    /**
     * 根据机构简称获取机构信息
     * @param abbreviation
     * @return
     */
    public OrganizationInfo getByAbbreviation(String abbreviation){
        return organizationInfoMapper.selectByAbbreviation(abbreviation);
    }

    /**
     * 根据机构编码获取机构信息
     *
     * @param orgCode
     * @return
     */
    public OrganizationInfo getOrgInfoByOrgCode(String orgCode) {
        return organizationInfoMapper.selectLastOneByOrgCodeAndStatus(orgCode, null);
    }

    @Transactional
    public OrganizationBaseConfigRespDTO selectOrganizationBaseConfigByOrgId(String orgId) {
        OrganizationBaseConfigRespDTO respDTO = new OrganizationBaseConfigRespDTO();
        OrganizationBaseConfig baseConfig = organizationBaseConfigMapperExt.selectByOrgId(orgId);
        log.info("查询机构配置,机构ID={},机构基础配置={}",orgId, JSON.toJSONString(baseConfig));
        if (null != baseConfig) {
            BeanUtils.copyProperties(baseConfig, respDTO);
            List<OrganizationLoanConfig> loanCofings = organizationLoanConfigMapperExt.selectByOrgIdForList(orgId);
            log.info("查询机构配置,机构ID={},机构基础配置={}",orgId, JSON.toJSONString(loanCofings));
            List<OrganizationLoanConfigRespDTO> configRespDTOList = new ArrayList<>();
            if (!loanCofings.isEmpty()) {
                for (OrganizationLoanConfig loanConfig : loanCofings) {
                    OrganizationLoanConfigRespDTO configRespDTO = new OrganizationLoanConfigRespDTO();
                    BeanUtils.copyProperties(loanConfig, configRespDTO);

                    // 后置平台管理费每期占比
                    List<BigDecimal> afterPlatformManageFeeRatioList = new ArrayList<>();
                    List<OrganizationManageFeeRatioConfig> organizationManageFeeRatioConfigList = organizationManageFeeRatioConfigMapperExt.selectByOrgLoanConfigId(loanConfig.getId());
                    for (int i = 0; i < organizationManageFeeRatioConfigList.size(); i++) {
                        OrganizationManageFeeRatioConfig ratioConfig = organizationManageFeeRatioConfigList.get(i);
                        if (ratioConfig.getCurrentPeriod() != i + 1) {
                            log.error("后置平台管理费每期占比配置错误：orgId={}, i={}, ratioConfig={}, organizationManageFeeRatioConfigList={}", orgId, i, JSON.toJSONString(ratioConfig), JSON.toJSONString(organizationManageFeeRatioConfigList));
                            throw new BizException("CONFIG_ERROR_10001");
                        }
                        afterPlatformManageFeeRatioList.add(ratioConfig.getManageFeePercent());
                    }

                    configRespDTO.setManageFeeChargeNode(loanConfig.getManageFeeChargeNode());
                    configRespDTO.setBeforePlatformManageFeeRate(loanConfig.getBeforePlatformManageFeeRate());
                    configRespDTO.setPlatformManageFeeRate(loanConfig.getAfterPlatformManageFeeRate());
                    configRespDTO.setAfterPlatformManageFeeRatioList(afterPlatformManageFeeRatioList);

                    configRespDTOList.add(configRespDTO);
                }
            }
            respDTO.setLoanConfigs(configRespDTOList);
        }
        log.info("查询机构配置,机构ID={},响应结果={}",orgId, JSON.toJSONString(respDTO));
        return respDTO;
    }

    @Transactional
    public boolean isFullFreezePerformance(String id) {
        OrganizationInfo organizationInfo = organizationInfoMapper.selectByPrimaryKey(id);
        return null != organizationInfo && organizationInfo.getPerformanceAmount().compareTo(
                organizationInfo.getFreezePerformanceAmount()) <= 0;
    }

    public Integer checkAgentUserRealName(String realName, String identityCard) {
        /**
         * 1:身份证号和姓名一致,2:身份证号和姓名不一致,3:查无此身份证号
         */
        Integer result = 0;

        VerNameRequset req = new VerNameRequset();

        req.setRealName(realName);
        req.setIdentityCard(identityCard);
        req.setFunctionCode(FunctionCodeEnum.QUERY_VERIFY_ID_NAME.getBodyFunctionCode());
        req.setTransDate(new Date());
        req.setTransNo(String.valueOf(System.currentTimeMillis()));

        VerNameResponse resp = null;
        try {
            CompletableFuture<VerNameResponse> future = tianchengVerNameService.tianchengVerName(req);
            resp = future.get(5L, TimeUnit.SECONDS);
            log.info("天秤鹏元二要素验证，request:{}, response:{}", JSON.toJSONString(req), JSON.toJSONString(resp));

            if (resp == null) {
                throw new BizException("USR19116");
            } else if (VerNameResponse.TianChengStatusEnum.TIAN_CHENG_STATUS_TRUE.getCode().equals(resp.getTianChengStatus())
                    && VerNameResponse.Status.STATUS_TRUE.getCode().equals(resp.getStatus())) {
                result = StringUtils.isBlank(resp.getCheckResult()) ? 3 : Integer.valueOf(resp.getCheckResult());
            } else {
                throw new BizException("USR19116");
            }
        } catch (Exception e) {
            log.error("天秤鹏元二要素出错，request:{}, response:{}", JSON.toJSONString(req), JSON.toJSONString(resp), e);
            throw new BizException("USR19116");
        }

        return result;
    }

    public BigDecimal getMaxOrgRate(){
        return organizationLoanConfigMapperExt.getOrgMaxRate();
    }


    /**
     * 根据机构代理用户名获取机构信息
     *
     * @param agentUserName 机构代理人用户名
     * @return 机构信息
     */
    public OrganizationInfoRespDTO selectOrganizationInfoByAgentUserName(String agentUserName) {
        OrganizationInfo organizationInfo = organizationInfoMapper.selectByAgentUserName(agentUserName);
        if (organizationInfo == null) {
            return null;
        }
        //解密敏感信息
        organizationInfo.setAgentIdentityCard(privacyMasks.decryptPrivacy(organizationInfo.getAgentIdentityCard()));
        organizationInfo.setAgentPhoneNumber(privacyMasks.decryptPrivacy(organizationInfo.getAgentPhoneNumber()));
        organizationInfo.setContactsPhoneName(organizationInfo.getContactsPhoneName() != null ? privacyMasks.decryptPrivacy(organizationInfo.getContactsPhoneName()) : null);

        OrganizationInfoRespDTO organizationInfoRespDTO = new OrganizationInfoRespDTO();
        BeanUtils.copyProperties(organizationInfo, organizationInfoRespDTO);

        return organizationInfoRespDTO;
    }

    public boolean sendSmsByLogin(String mobliePhone) {
        MessageTemplateDto sysSmsTemplateRespDTO = sysMessageTemplate.selectByTemplateCode(OrgRedisConstants.LOGIN_TEMPLATE_CODE);
        String sdate = FastDateFormat.getInstance("yyyyMMdd").format(new Date());
        String codeKey = OrgRedisConstants.verify_CODE_PREFIX + mobliePhone + "-" + sdate;
        String code = getSmsCode(6, "0123456789".toCharArray());
        // 测试 开发环境默认使用同一个值
        // if (profile != null &&
        // ("test".equalsIgnoreCase(profile)||"default".equalsIgnoreCase(profile)||"dev-online".equalsIgnoreCase(profile)))
        // {
        // code="888888";
        // }
        String nextKey = OrgRedisConstants.VERIFY_CODE_PREFIX_NEXT + mobliePhone + "-" + sdate;
        // 短信失效时间5分钟
        stringRedisTemplate.opsForValue().set(codeKey, code, OrgRedisConstants.CODE_EXPIRE_TIME, TimeUnit.SECONDS);
        log.info("保存验证码codeKey={}, code={}到Redis", codeKey, code);
        // 两次发送间隔一分钟
        stringRedisTemplate.opsForValue().set(nextKey, code, OrgRedisConstants.VERIFY_CODE_EXPIRE_TIME, TimeUnit.SECONDS);

        CompletableFuture<Boolean> result;
        if (isEnableSMS()) {
            result = smsSendService.sendNormal(mobliePhone,
                    sysSmsTemplateRespDTO.getTemplateValue(), null, code);
        } else {
            result = CompletableFuture.supplyAsync(()->true);
        }
        SMSRecord smsRecord = new SMSRecord();
        smsRecord.setAuthCode(code);
        smsRecord.setBusinessType((byte) 2);
        smsRecord.setCreateTime(new Date());
        smsRecord.setId(snowflakeIdWorker.nextId());
        smsRecord.setMobileNo(privacyMasks.encryptPrivacy(mobliePhone));
        smsRecordMapperExt.insert(smsRecord);
        try {
            return result.get();
        } catch (InterruptedException | ExecutionException e) {
            return false;
        }
    }

    private String getSmsCode(int codeLen, char[] metadata) {
        if (metadata == null) {
            metadata = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".toCharArray();
        }
        StringBuilder stringBuilder = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < codeLen; i++) {
            int index = random.nextInt(metadata.length);
            stringBuilder.append(metadata[index]);
        }
        return stringBuilder.toString();
    }

    public int updatePassword(OrganizationInfoReqDTO organizationInfoReqDTO) {
        OrganizationInfo organizationInfo = new OrganizationInfo();
        organizationInfo.setId(organizationInfoReqDTO.getId());
        organizationInfo.setPassword(organizationInfoReqDTO.getPassword());
        organizationInfo.setSalt(organizationInfoReqDTO.getSalt());
        organizationInfo.setNeedUpdatePassword("0");
        return organizationInfoMapper.updateByPrimaryKeySelective(organizationInfo);
    }

    public OrganizationInfo getOrgInfoBySocialCreditCode(String unifiedSocialCreditCode) {
        OrganizationInfo organizationInfo = null;
        if(StringUtils.isNotBlank(unifiedSocialCreditCode)) {
            List<OrganizationInfo>  organizationInfoList = organizationInfoMapper.selectOrgBySocialCreditCode(unifiedSocialCreditCode);
            if(CollectionUtils.isNotEmpty(organizationInfoList)) {
                organizationInfo = organizationInfoList.get(0);
            }
        }
        return organizationInfo;
    }
}
